package guava;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.*;
import com.google.common.primitives.Ints;
import org.junit.Test;
import org.xukai.common.ComparableStudent;

import javax.annotation.Nullable;
import java.util.*;

import static org.junit.Assert.assertEquals;

/**
 * @author xukai
 * @desc
 * @date 2016-11-30-上午 7:31
 */
public class CollectionUtil {

    /**
     * FluentIterable
     * @throws Exception
     */
    @Test
    public void testTransform() throws Exception {
        ComparableStudent s1 = new ComparableStudent("d", 22, 3);
        ComparableStudent s2 = new ComparableStudent("d2", 222, 32);
        List<ComparableStudent> students = Arrays.asList(s1, s2);
        List<String> transformedList =
                FluentIterable.from(students).transform(new Function<ComparableStudent,String>() {
                    @Override
                    public String apply(ComparableStudent input) {
                        return Joiner.on('#').join(input.getName(),
                                input.getScore(), input.getAge());
                    }
                }).toList();
        assertEquals("d2#32#222",transformedList.get(1));
        Iterable<ComparableStudent> concat = Iterables.concat(students);
        Iterables.tryFind(students, new Predicate<ComparableStudent>() {
            @Override
            public boolean apply(@Nullable ComparableStudent input) {
                return false;
            }
        });

    }

    /**
     * Iterables
     * @throws Exception
     */
    @Test
    public void testIterables() throws Exception {

    }

    /**
     * Sets
     */
    @Test
    public void SetsTest(){
        Set<String> s1 = Sets.newHashSet("1","2","3");
        Set<String> s2 = Sets.newHashSet("2","3","4");
        Sets.SetView<String> sv1 = Sets.difference(s1, s2);//[1]
        Sets.SetView<String> sv2 = Sets.intersection(s1, s2); // [2, 3]
        Sets.SetView<String> sv3 = Sets.union(s1, s2); // [3, 2, 1 ,4]
        Sets.SetView setView = Sets.symmetricDifference(s1,s2);//[1,4]
    }

    /**
     * MultiSet
     */
    @Test
    public void MultiSetTest(){
        Multiset<String> set = HashMultiset.create();
        set.add("a");
        set.add("b");
        set.add("c");
        set.add("a");
        int a = set.count("a");
        assertEquals(a,2);

    }

    /**
     * Maps
     */
    @Test
    public void MapsTest(){
//      iterator各个元素作为Map.values, key为Function.apply返回值
        System.out.println(Integer.MAX_VALUE);
        ArrayList<ComparableStudent> list = Lists.newArrayList(new ComparableStudent());
        List<ComparableStudent> exactly100 = Lists.newArrayListWithCapacity(100);
        List<ComparableStudent> approx100 = Lists.newArrayListWithExpectedSize(100);
        Set<ComparableStudent> approx100Set = Sets.newHashSetWithExpectedSize(100);
        List countUp = Ints.asList(1, 2, 3, 4, 5);
        List countDown = Lists.reverse(countUp); // {5, 4, 3, 2, 1}
        List<List> parts = Lists.partition(countUp, 2);//{{1,2}, {3,4}, {5}}
        ComparableStudent s1 = new ComparableStudent("d", 22, 3);
        ComparableStudent s2 = new ComparableStudent("d2", 222, 32);
        List<ComparableStudent> students = Arrays.asList(s1, s2);
        ImmutableMap<String, ComparableStudent> map = Maps.uniqueIndex(students, new Function<ComparableStudent, String>() {
            @Override
            public String apply(ComparableStudent p) {
                return p.getName();
            }
        });
        System.out.println(map.size());

        ImmutableSet digits = ImmutableSet.of("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
        Function<String, Integer> lengthFunction = new Function<String, Integer>() {
            public Integer apply(String string) {
                return string.length();
            }
        };

        ImmutableListMultimap<Integer, String> digitsByLength= Multimaps.index(digits, lengthFunction);
        /*
        *  digitsByLength maps:
        *  3 => {"one", "two", "six"}
        *  4 => {"zero", "four", "five", "nine"}
        *  5 => {"three", "seven", "eight"}
        */

    }

    /**
     * Multimap
     * LinkedHashMultimap //顺序的HashMultimap, 形如LinkedHashMap
     * TreeMultimap //可排序的MultiMap, 形如TreeMap
     * 一些不可变的map
     * HashMultimap
     * ImmutableListMultimap
     * ImmutableMultimap
     * ImmutableSetMultimap
     */
    @Test
    public void testArrayListMultimapSameKeyValue(){
        ArrayListMultimap<String,String> multiMap =
                ArrayListMultimap.create();
        multiMap.put("Bar","1");
        multiMap.put("Bar","2");
        multiMap.put("Bar","3");
        multiMap.put("Foo","3");
        multiMap.put("Foo","3");
        List<String> expected = Lists.
                newArrayList("1","2","3");
        assertEquals(multiMap.get("Bar"),expected);
        assertEquals(5,multiMap.size());
        List<String> expected2 = Lists.
                newArrayList("1","2","3","3","3");
        assertEquals(expected2,Lists.newArrayList(multiMap.values().iterator()));
        ArrayListMultimap<String,String> multiMap1 = ArrayListMultimap.create();
        int numExcpectedKeys = 5;
        int numExpectedValuesPerKey = 5;
        ArrayListMultimap<String,String> multiMap2 = ArrayListMultimap.create(numExcpectedKeys,numExpectedValuesPerKey);
        ArrayListMultimap<String,String> mulitMap3 =ArrayListMultimap.create(multiMap);
    }

    /**
     * immutable不可变集合
     */
    @Test
    public void testImmutable() throws Exception {
        ImmutableSet<String> set = ImmutableSet.of("a", "b", "c");
        ImmutableMap<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);
        ImmutableSortedSet<String> sortedSet = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
    }

    /**
     * BiMap
     */
    @Test
    public void testBiMapForcePut() throws Exception {
        BiMap<String,String> biMap = HashBiMap.create();
        biMap.put("1","Tom");
        //强制覆盖
        biMap.forcePut("2","Tom");
        assertEquals(biMap.containsKey("1"),false);
        assertEquals(biMap.containsKey("2"),true);
        assertEquals(biMap.inverse().get("Tom"),"2");
    }

    /**
     * HashBasedTable
     * ArrayTable //二维数组实现
     * TreeBasedTable //对行列排序的table
     * ImmutableTable //不可变table，创建后不能改变
     */
    @Test
    public void testHashBasedTable() throws Exception {
//        HashBasedTable<Integer, Integer, String> table = HashBasedTable.create();
//        table.put(1, 1, "Rook");
//        table.put(1, 2, "Knight");
//        table.put(1, 3, "Bishop");
//        System.out.println(table.contains(1, 1)); //true
//        System.out.println(table.containsColumn(2)); //true
//        System.out.println(table.containsRow(1)); //true
//        System.out.println(table.containsValue("Rook")); //true
//        System.out.println(table.remove(1, 3)); //Bishop
//        System.out.println(table.get(3, 4)); //null
//        Map<Integer,String> columnMap = table.column(1);
//        System.out.println(columnMap.size());
//        Map<Integer,String> rowMap = table.row(1);
//        System.out.println(rowMap.size());



    }

    /**
     * Range
     */
    public void TestRange(){
        Range<Integer> numberRange = Range.closed(1, 10); //包括首尾
        System.out.println(numberRange.contains(10)); //true
        System.out.println(numberRange.contains(1)); //true

        Range<Integer> numberRange1 = Range.open(1,10); //除去首尾
        System.out.println(numberRange1.contains(10)); //false
        System.out.println(numberRange1.contains(1)); //false
        Range<Integer> ageRange = Range.closed(35, 50);
        //Person到age转换的function
        Function<ComparableStudent, Integer> ageFunction = new Function<ComparableStudent, Integer>() {
            @Override
            public Integer apply(ComparableStudent student) {
                return student.getAge();
            }
        };
        //这样得到年龄再[35, 50]之间的人
        Predicate<ComparableStudent> predicate = Predicates.compose(ageRange,ageFunction);
    }

    /**
     * Immutable
     */
    @Test
    public void TestImmutable(){
        ImmutableMultimap<Integer, String> multimap = new ImmutableListMultimap.Builder<Integer, String>()
                .put(1, "Foo")
                .putAll(2, "Foo", "Bar", "Baz")
                .putAll(4, "Huey", "Duey", "Luey")
                .put(3, "Single").build();
    }

    /**
     * Ordering
     */
    public class CityByScore implements Comparator<ComparableStudent> {
        @Override
        public int compare(ComparableStudent city1, ComparableStudent city2) {
            return Ints.compare(city1.getScore(),city2.getScore());
        }
    }
    public class CityByAge implements Comparator<ComparableStudent> {
        @Override
        public int compare(ComparableStudent city1, ComparableStudent city2) {
            return Ints.compare(city1.getAge(),city2.getAge());
        }
    }
    @Test
    public void testSecondarySort(){
        ComparableStudent student1 = new ComparableStudent("xukai1", 22, 98);
        ComparableStudent student2 = new ComparableStudent("xukai2", 23, 66);
        ComparableStudent student3 = new ComparableStudent("xukai3", 21, 87);
        List<ComparableStudent> cities = Lists.newArrayList(student1,student2,student2);
        Ordering<ComparableStudent> secondaryOrdering = Ordering.from(new CityByScore()).compound(new CityByAge());
        ComparableStudent students = secondaryOrdering.min(cities.iterator());
//        System.out.println(students.size() + "  " + students.get(0).toString());
        System.out.println(students.toString());
        Collections.sort(cities,secondaryOrdering);
    }




}
